package com.xing.cglib.mytest.weave;

import com.xing.cglib.mytest.Interceptor;
import org.objectweb.asm.*;
import org.objectweb.asm.commons.Method;
import org.objectweb.asm.tree.*;

public class WeavUtil {

    public static final Type WEAVER_TYPE = Type.getType(Interceptor.class);

    public static final Method CALL_ORIGINAL_METHOD = new Method("intercept", Type.getType(Object.class), new Type[0]);

    public static ClassNode convertToClassNode(byte[] classBytes) {
        ClassReader reader = new ClassReader(classBytes);
        ClassNode result = new SynchronizedClassNode(327680);
        reader.accept(result, 4);
        return result;
    }

    public static MethodNode getMethodNode(ClassNode classnode, String methodName, String methodDesc) {
        for (Object method : classnode.methods) {
            MethodNode methodNode = (MethodNode) method;
            if ((methodNode.name.equals(methodName)) && (methodNode.desc.equals(methodDesc))) {
                return methodNode;
            }
        }
        return null;
    }

    public static boolean isOriginalMethodInvocation(String owner, String name, String desc) {
        return (owner.equals(WEAVER_TYPE.getInternalName())) && (name.equals(CALL_ORIGINAL_METHOD.getName())) && (desc.equals(CALL_ORIGINAL_METHOD.getDescriptor()));
    }

    public static MethodInsnNode findOriginalIndex(InsnList instructions) {
        int size = instructions.size();
        for (int i = 0; i < size; i++) {
            AbstractInsnNode insn = instructions.get(i);
            if (insn.getType() == 5) {
                MethodInsnNode methodInsn = (MethodInsnNode) insn;
                if (isOriginalMethodInvocation(methodInsn.owner, methodInsn.name, methodInsn.desc)) {
                    return methodInsn;
                }
            }
        }
        return null;
    }

    public static byte[] getClassByteArray(String className) throws Exception{
        ClassReader cr = new ClassReader(className);
        ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);
        ClassVisitor cv = new NopClassVistor(Opcodes.ASM5, cw);
        cr.accept(cv, Opcodes.ASM5);
        return cw.toByteArray();
    }

}
